package com.senseauto.mediarecorder;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaCodec;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

/**
 * 视频打开的时候就打开摄像头预览画面，然后点击开始录制的时候开始录视频，用MediaRecorder录制
 */
public class RecordActivity extends AppCompatActivity implements View.OnClickListener {
    String TAG = "RecordActivity";
    TextureView textureView;
    Button btnRecord;
    int cameraId = 0;//车机摄像头id 47 平板和手机摄像头id 0
    boolean isRecording = false;

    private CameraManager cameraManager;
    private HandlerThread mCameraThread;
    private Handler cameraHandler;
    private Size mPreviewSize;
    private CameraDevice cameraDevice;
    private SurfaceTexture surfaceTexture;
    private CameraCaptureSession captureSession;
    private ImageReader imageReader;
    private Handler mHandler = new Handler(Looper.getMainLooper());

    private MediaRecorder mediaRecorder;
    private Surface mRecordSurface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_record);
        textureView = findViewById(R.id.texture);
        mPreviewSize = new Size(1920, 1080);
        //mPreviewSize = new Size(2560, 1920);

        mediaRecorder = new MediaRecorder();


        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @RequiresApi(api = Build.VERSION_CODES.M)
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                surfaceTexture = surface;
                configureTransform(width, height);
                initCamera();

            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
                Log.e(TAG, "onSurfaceTextureSizeChanged->configureTransform");

            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

            }
        });
        btnRecord = findViewById(R.id.record);
        btnRecord.setOnClickListener(this);

    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    public void initCamera() {

        //左右镜像问题
        //textureView.setScaleX(-1f);
        initHandler();
        cameraManager = getSystemService(CameraManager.class);


        imageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.YUV_420_888, 2);
        imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = reader.acquireLatestImage();
                if (image != null) {


                    image.close();
                }
            }
        }, mHandler);
        Log.e(TAG, "initCamera() mCameraFactory.openCamera()");
        openCamera();
    }

    //旋转屏幕画面
    private void configureTransform(int viewWidth, int viewHeight) {
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mPreviewSize.getHeight(),
                    (float) viewWidth / mPreviewSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        } else if (Surface.ROTATION_180 == rotation) {
            matrix.postRotate(180, centerX, centerY);
        }
        textureView.setTransform(matrix);
    }

    private void openCamera() {

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            Log.e(TAG, "没有摄像头权限");
            return;
        }
        try {
            cameraManager.openCamera(cameraId + "", new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    cameraDevice = camera;
                    createCaptureSession(camera);
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {

                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {

                }
            }, cameraHandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void initHandler() {
        mCameraThread = new HandlerThread("CameraThread");
        mCameraThread.start();
        cameraHandler = new Handler(mCameraThread.getLooper());
    }

    private CameraCaptureSession.CaptureCallback mCaptureCallBack = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
        }

        @Override
        public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
            super.onCaptureFailed(session, request, failure);
            Log.e(TAG, "onCaptureFailed");
        }

        @Override
        public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
            super.onCaptureStarted(session, request, timestamp, frameNumber);
        }
    };

    private void createCaptureSession(CameraDevice cameraDevice) {
        try {

            CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            Surface surface = new Surface(surfaceTexture);
            builder.addTarget(surface);
            builder.addTarget(imageReader.getSurface());

            builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自动对焦
            builder.set(CaptureRequest.JPEG_ORIENTATION, 0);//横屏可以不用旋转，竖屏需要顺时针旋转90度

            ArrayList<Surface> sessionSurfaces = new ArrayList<>();
            sessionSurfaces.add(surface);
            sessionSurfaces.add(imageReader.getSurface());

            cameraDevice.createCaptureSession(sessionSurfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    Log.e(TAG, "Session创建好了");
                    captureSession = session;
                    try {
                        captureSession.setRepeatingRequest(builder.build(), mCaptureCallBack, mHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                }
            }, cameraHandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onResume() {
        super.onResume();

    }

    @Override
    public void onPause() {
        super.onPause();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        releaseCamera();
    }

    public void releaseCamera() {
        if (captureSession != null) {
            captureSession.close();
            captureSession = null;
        }

        cameraDevice.close();
        cameraDevice = null;

        if (imageReader != null) {
            imageReader.close();
            imageReader = null;
        }

        releaseThread();
    }

    public void releaseThread() {
        mCameraThread.quitSafely();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            case R.id.record:
                if (!isRecording) { //不在录制，开启录制
                    Log.e(TAG, "isRecording =false 不在录制，马上开始录制！！");
                    isRecording = true;
                    //回调拿到的数据会写入文件，最后停止录制会最多保留3个文件
                    preparedRecorder();
                    recordStart();
                    btnRecord.setTextColor(getResources().getColor(R.color.red));
                    btnRecord.setText(getResources().getString(R.string.text_recording));
                } else {
                    Log.e(TAG, "isRecording =true 停止录制！！");

                    //停止录制
                    isRecording = false;
                    recordStop();
                    try {
                        captureSession.stopRepeating();
                        captureSession.close();
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                    createCaptureSession(cameraDevice);
                    btnRecord.setTextColor(getResources().getColor(R.color.black));
                    btnRecord.setText(getResources().getString(R.string.text_record));
                }
                break;
        }
    }

    private void preparedRecorder() {
        //将原来的预览停了
        try {
            captureSession.stopRepeating();
            captureSession.close();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        configRecorder();
    }
    private void recordStart(){
        createRecordSession();
    }
    private void configRecorder() {
        try {
            if(mRecordSurface == null){
                mRecordSurface = MediaCodec.createPersistentInputSurface();
            }
            //如果MediaRecorder不支持这个编码尺寸，会报错 Unsupported set of inputs/outputs provided
            mediaRecorder.setInputSurface(mRecordSurface);

            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); // 设置视频来源
            mediaRecorder.setVideoEncodingBitRate(mPreviewSize.getWidth() * mPreviewSize.getHeight() * 8); // 设置比特率
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频来源
            mediaRecorder.setAudioEncodingBitRate(96000);  // 设置音频编码比特率（一般音乐和语音录制）
            mediaRecorder.setAudioSamplingRate(44100);  // 设置音频采样率（CD音质）
            mediaRecorder.setCaptureRate(30); // 捕获率
            mediaRecorder.setOrientationHint(0);  // 设置录制视频时的预期方向，取值为 0、90、180 或 270

            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 设置输出格式
            mediaRecorder.setVideoSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());  // 设置视频宽高
            mediaRecorder.setVideoFrameRate(30); // 设置帧数
            mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频编码格式
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); // 设置音频编码格式

            File file = getExternalCacheDir();
            String videoName = new SimpleDateFormat("yyyy_MM_dd_HH_ss_SSS").format(new Date()) + ".mp4";
            File outputFile = new File(file, videoName);
            Log.e(TAG, "outputFile=" + outputFile.getAbsolutePath());
            mediaRecorder.setOutputFile(outputFile.getAbsolutePath());
            mediaRecorder.prepare();

            Log.e(TAG, "开始录制");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void recordStop() {
        if (mediaRecorder != null) {
            mediaRecorder.stop();  // 停止录制
            mediaRecorder.reset();
            mediaRecorder.release();  // 释放
        }
    }
    private void createRecordSession(){
        SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
        Surface previewSurface = new Surface(surfaceTexture);
        Surface recorderSurface = mRecordSurface;//从获取录制视频需要的Surface

        try {
            //camera record process，step3 创建CaptureRequest.Build 对象，并用CameraDevice.TEMPLATE_RECORED 参数初始化
            CaptureRequest.Builder mPreviewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            //camera record process，step4 将MediaRecorder和预览用的Surface实例添加到该请求的目标列表中
            mPreviewRequestBuilder.addTarget(previewSurface);
            mPreviewRequestBuilder.addTarget(recorderSurface);
            //请注意这里设置了Arrays.asList(previewSurface,recorderSurface) 2个Surface，很好理解录制视频也需要有画面预览，第一个是预览的Surface，第二个是录制视频使用的Surface
            //camera record process，step5 执行CameraDevice.CreateCaptureSession 方法
            cameraDevice.createCaptureSession(Arrays.asList(previewSurface,recorderSurface),new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    captureSession = session;
                    Log.i(TAG, "Video Session:" + captureSession.toString());
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
                    cameraHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                captureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, cameraHandler);
                            } catch (CameraAccessException e) {
                                throw new RuntimeException("Can't visit camera");
                            }
                        }
                    });
                    mediaRecorder.start();
                }
                @Override
                public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                }
            },cameraHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }
}